#pragma once
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>
#include "Common.hpp"
#include "Log.hpp"

namespace wxd
{
    const std::string default_root = "./wwwroot";
    const std::string sep = "\r\n";
    const std::string middle_sep = ": ";
    const std::string middle_space = " ";
    const std::string not_found_path = default_root + "/404.html";
    const std::string content_type_path = "./ContentType.txt";
    class HttpRequest
    {

    private:
        void SetHead()
        {
            for (auto head : _request_heads)
            {
                std::string key, value;
                // 提取key value
                bool ret = ParseKeyValue(head, key, value, middle_sep);
                if (!ret)
                {
                    LOG(LogLevel::ERROR) << "parse head err";
                    return;
                }
                //_request_heads_map.insert(std::make_pair(key,value));
                _request_heads_map.emplace(key, value);
            }
        }


    public:
        // 反序列化
        bool Deserialize(std::string &request_str)
        {
            std::string line;
            // 按行解析的方法
            int ret = ParseOneLine(request_str, line, sep);
            if (!ret)
                return false;
            // 将请求行填入
            _request_line = line;
            // 细化请求行
            std::stringstream ss(_request_line);
            ss >> _method >> _uri >> _http_version;

            // 按行解析，填入请求头
            // 解析成功 内容非空 说明读到了请求报头
            // 解析成功 空 说明读到了空行
            while (ParseOneLine(request_str, line, sep))
            {
                // 读到空行
                if (line.empty())
                {
                    _blank_line = sep;
                    break;
                }

                _request_heads.emplace_back(line);
            }
            // 细化请求报头
            SetHead();
            // 填入请求体
            _body = request_str;

            // 判断是否带参
            if (_method == "POST")
            {
                // 默认POST一定带参
                // 设置方法键值
                _func_path = _uri;
                // 设置方法参数
                _func_args = _body;
                _is_exe = true;
            }
            else if (_method == "GET")
            {
                // 如果有？说明带参
                size_t pos = _uri.find("?");
                if (pos != std::string::npos)
                {
                    // 带参
                    // 设置方法键值
                    _func_path = _uri.substr(0, pos);
                    // 设置方法参数
                    _func_args = _uri.substr(pos+1);
                    _is_exe = true;
                }
            }
            return true;
        }

        void PrintDebug() const
        {
            LOG(LogLevel::DEBUG) << "_method# " << _method;
            LOG(LogLevel::DEBUG) << "_uri# " << _uri;
            LOG(LogLevel::DEBUG) << "_http_version# " << _http_version;
            // for (auto &head : _request_heads)
            // {
            //     LOG(LogLevel::DEBUG) << head;
            // }
            for (auto &head : _request_heads_map)
            {
                LOG(LogLevel::DEBUG) << head.first << "# " << head.second;
            }
            LOG(LogLevel::DEBUG);
            LOG(LogLevel::DEBUG) << "_body#" << _body;
        }
        // 重置uri
        void ResetUri()
        {
            _uri = default_root + _uri;
            if (_uri.back() == '/')
            {
                _uri += "index.html";
            }
        }
        void ResetUri(const std::string &path)
        {
            _uri = path;
        }
        // 返回uri
        std::string GetUri() const
        {
            return _uri;
        }
        // 返回请求资源的内容
        std::string GetContent() const
        {
            // // 暂做读取字符串处理
            // // 打开文件流
            // std::ifstream in(_uri);
            // // 访问资源不存在，返回空
            // if (!in.is_open())
            //     return std::string();
            // // 访问资源存在
            // std::string line;
            // std::string content;
            // // 逐行读取
            // while (getline(in, line))
            // {
            //     content += line;
            // }
            // return content;

            // 以二进制方式读取
            std::string content;
            std::ifstream in(_uri, std::ios::binary);
            if (!in.is_open())
                return std::string();
            // 获取文件大小
            in.seekg(0, in.end);
            size_t file_size = in.tellg();
            in.seekg(0, in.beg);
            content.resize(file_size); // 提前开辟好空间
            in.read((char *)content.c_str(), file_size);
            return content;
        }

        bool IsExe()const
        {
            return _is_exe;
        }
        std::string FuncPath()const
        {
            return _func_path;
        }
        std::string FuncArgs()const
        {
            return _func_args;
        }
    private:
        // 按行解析
        std::string _request_line;               // 请求行
        std::vector<std::string> _request_heads; // 请求报头
        std::string _blank_line;                 // 空行
        std::string _body;                       // 请求体

        // 细化
        std::string _method;                                             // 请求方法
        std::string _uri;                                                // uri-资源路径
        std::string _http_version;                                       // 协议版本
        std::unordered_map<std::string, std::string> _request_heads_map; // 请求报头

        // 方法
        std::string _func_path; // 方法名字  /login
        std::string _func_args; // 方法参数
        bool _is_exe = false;
    };

    class HttpResponse
    {
        const std::string default_http_version = "HTTP/1.0";

    public:
        
        HttpResponse()
        {
            
        }
        // 用于静态请求，自动构建response
        void Build(HttpRequest &request)
        {
            // // 测试重定向
            // _http_version = default_http_version;
            // _status_code = 302;
            // SetCodeDesc();
            // SetRetHead("Location","https://www.qq.com/");

            // 设置协议版本
            _http_version = default_http_version;

            // 重置Uri(补全根目录/首页)
            request.ResetUri();
            // 设置状态码-先简单设置
            if (request.GetContent() == "") // 访问资源不存在
            {
                _status_code = 404;
                request.ResetUri(not_found_path); // 重定向到404页面
            }
            else
                _status_code = 200;
            // 设置状态码描述

            // 设置响应报头
            // Content-Length
            SetRetHead("Content-Length", std::to_string(request.GetContent().size()));
            // Content-Type
            std::string content_type = InitContentType(request.GetUri());
            SetRetHead("Content-Type", content_type);
            // 设置空行
            _blank_line = sep;
            //  设置响应体
            _body = request.GetContent();
        }
        

        void SetCodeDesc()
        {
            switch (_status_code)
            {
            case 200:
                _status_code_desc = "OK";
                break;
            case 404:
                _status_code_desc = "Not Fonud";
                break;
            case 302:
                _status_code_desc = "Fonud";
                break;
            default:
                _status_code_desc = "Unknown";
                break;
            }
        }
        // 序列化-将序列化后的结果带出
        bool Serialize(std::string &response_str)
        {
            // 设置响应行
            response_str = (_http_version + middle_space + std::to_string(_status_code) + middle_space + _status_code_desc + sep);
            // 设置响应报头
            for (auto &head : _response_heads)
            {
                response_str += head;
            }
            //  设置空行
            response_str += _blank_line;
            // 设置响应体
            response_str += _body;

            return true;
        }

        void SetRetHead(const std::string &key, const std::string &value)
        {
            std::string head = key + middle_sep + value + sep;
            _response_heads.push_back(head);
        }

        std::string InitContentType(const std::string &uri)
        {
            std::ifstream in(content_type_path);
            if (!in.is_open())
            {
                LOG(LogLevel::ERROR) << "content_type_path open fail!";
                return "text/html";
            }
            std::string line;
            while (getline(in, line))
            {
                std::string key, value;
                ParseKeyValue(line, key, value, middle_sep);
                _content_types.emplace(key, value);
            }
            size_t pos = uri.rfind(".");
            std::string suffix = uri.substr(pos);
            // LOG(LogLevel::DEBUG)<<suffix;
            // for(auto& type:_content_types)
            // {
            //     LOG(LogLevel::DEBUG)<<type.first<<"#"<<type.second;
            // }
            return _content_types[suffix];
        }

    private:
        std::string _http_version;                // 协议版本
        int _status_code;                         // 状态码
        std::string _status_code_desc;            // 状态码描述
        std::vector<std::string> _response_heads; // 响应报头
        std::string _blank_line;
        std::string _body;                                           // 响应体
        std::unordered_map<std::string, std::string> _content_types; // 数据类型
    };
}
